﻿using System;

namespace Systemathics.FrameWork
{
    public sealed class SmartOrders : IDisposable
    {
        private readonly Instrument instrument;
        private OrderSide smartOrderSide;
        private OrderStyle smartOrderStyle;
        private int smartOrderQuantity;
        private decimal smartOrderPrice;
        private readonly OrderExtension ext;
        private readonly Guid stratId;
        private decimal Amount;

        private bool isBracketOrder, smartOrderNotYetActivated;
        private bool canUseAnotherSmartOrder;

        public SmartOrders(Instrument i, Guid stratId)
        {
            instrument = i;
            this.stratId = stratId;
            instrument.OnBlotter += OnBlotter;
            ext = new OrderExtension(){Tif = TimeInForce.FillOrKill};
            isBracketOrder = false;
            smartOrderNotYetActivated = false;
            canUseAnotherSmartOrder = true;

        }

        public void StopMarketOrder(OrderSide side, int Qty, decimal stopPrice)
        {
            if (canUseAnotherSmartOrder)
            {
                canUseAnotherSmartOrder = false;
                smartOrderSide = side;
                smartOrderQuantity = Qty;
                smartOrderPrice = stopPrice;
                smartOrderStyle = OrderStyle.Stop;
                smartOrderNotYetActivated = true;
                instrument[Expo.Working].Add(smartOrderSide, smartOrderQuantity, smartOrderPrice);
                new RemotingLogClient().Trace(new FireMessageEventArgs(side + " Market Stop Order working for: " + instrument.StaticData.Name + " - Stop: " + smartOrderPrice, Time.Now.TimeOfDay));
            }
        }
        public void StopLimitOrder(OrderSide side, int Qty, decimal stopPrice)
        {
            if (canUseAnotherSmartOrder )
            {
                canUseAnotherSmartOrder = false;
                smartOrderSide = side;
                smartOrderQuantity = Qty;
                smartOrderPrice = stopPrice;
                smartOrderStyle = OrderStyle.StopLimit;
                smartOrderNotYetActivated = true;
                instrument[Expo.Working].Add(smartOrderSide, smartOrderQuantity, smartOrderPrice);
                new RemotingLogClient().Trace(new FireMessageEventArgs(side + " Limit Stop Order working for: " + instrument.StaticData.Name + " - Stop: " + smartOrderPrice, Time.Now.TimeOfDay));
            }
        }
        public void TrailStopLimitOrder(OrderSide side, int Qty, decimal stopPrice, decimal amount)
        {
            if (canUseAnotherSmartOrder)
            {
                canUseAnotherSmartOrder = false;
                this.smartOrderSide = side;
                this.smartOrderQuantity = Qty;
                smartOrderPrice = stopPrice;
                smartOrderStyle = OrderStyle.TrailingStopLimit;
                Amount = amount;
                smartOrderNotYetActivated = true;
                instrument[Expo.Working].Add(smartOrderSide, smartOrderQuantity, smartOrderPrice);
                new RemotingLogClient().Trace(new FireMessageEventArgs(side + " Limit Trail Stop Order working for: " + instrument.StaticData.Name + " - Stop: " + smartOrderPrice + " - Amount: " + amount, Time.Now.TimeOfDay));
            }
        }
        public void TrailStopMarketOrder(OrderSide side, int Qty, decimal stopPrice, decimal amount)
        {
            if (canUseAnotherSmartOrder)
            {
                canUseAnotherSmartOrder = false;
                this.smartOrderSide = side;
                this.smartOrderQuantity = Qty;
                smartOrderPrice = stopPrice;
                smartOrderStyle = OrderStyle.TrailingStop;
                Amount = amount;
                smartOrderNotYetActivated = true;
                instrument[Expo.Working].Add(smartOrderSide, smartOrderQuantity, smartOrderPrice);
                new RemotingLogClient().Trace(new FireMessageEventArgs(side + " Market Trail Stop Order working for: " + instrument.StaticData.Name + " - Stop: " + smartOrderPrice + " - Amount: " + amount, Time.Now.TimeOfDay));
            }
        }

        private Decimal TakeProfitBracket, StopLossBracket;
        public void BracketOrder(OrderSide orderSide, int qty, decimal takeProfitPrice, decimal stopLosssPrice)
        {
            if (canUseAnotherSmartOrder)
            {
                smartOrderQuantity = qty;
                TakeProfitBracket = takeProfitPrice;
                StopLossBracket = stopLosssPrice;
                var prc = instrument.Blotter[QuoteLevel.One].Mid;

                switch (orderSide)
                {
                    case OrderSide.Buy:
                        if (TakeProfitBracket < prc && prc < StopLossBracket)
                        {
                            isBracketOrder = true;
                            smartOrderNotYetActivated = true;
                            canUseAnotherSmartOrder = false;
                            smartOrderSide = OrderSide.Buy;
                            instrument[Expo.Working].Add(OrderSide.Buy, smartOrderQuantity, takeProfitPrice);
                            new RemotingLogClient().Trace(new FireMessageEventArgs(instrument.StaticData.Name + ": Buy Bracket Order Working: Take Profit/Stop Loss @" + takeProfitPrice + "/" + stopLosssPrice, Time.Now.TimeOfDay));
                            new RemotingLogClient().Trace(new FireMessageEventArgs(OrderSide.Buy + " Limit Stop Order working for: " + instrument.StaticData.Name + " - Stop: " + smartOrderPrice, Time.Now.TimeOfDay));
                        }
                        else
                            new RemotingLogClient().Trace(new FireMessageEventArgs(instrument.StaticData.Name + ": Bracket Order Not Valid: Take Profit > currrent price or Stop Loss < current Price", Time.Now.TimeOfDay));

                        break;
                    case OrderSide.Sell:
                        if (StopLossBracket < prc && prc < TakeProfitBracket)
                        {
                            isBracketOrder = true;
                            smartOrderNotYetActivated = true;
                            canUseAnotherSmartOrder = false;
                            smartOrderSide = OrderSide.Sell;
                            instrument[Expo.Working].Add(OrderSide.Sell, smartOrderQuantity, takeProfitPrice);
                            new RemotingLogClient().Trace(new FireMessageEventArgs(instrument.StaticData.Name  + ": Sell Bracket Order Working: Take Profit/Stop Loss @" + takeProfitPrice + "/" + stopLosssPrice, Time.Now.TimeOfDay));
                        }
                        else
                            new RemotingLogClient().Trace(new FireMessageEventArgs(instrument.StaticData.Name + ": Bracket Order Not Valid: Take Profit < currrent price or Stop Loss > current Price", Time.Now.TimeOfDay));

                        break;
                }
              
            }
        }
        public void LimitOnclose(OrderSide side, int qty, Decimal price)
        {
            if (canUseAnotherSmartOrder)
            {
                canUseAnotherSmartOrder = false;
                smartOrderSide = side;
                smartOrderQuantity = qty;
                smartOrderPrice = price;
                smartOrderStyle = OrderStyle.LimitOnClose;
            }
        }
        public void MarketOnclose(OrderSide side, int qty)
        {
            if (canUseAnotherSmartOrder)
            {
                canUseAnotherSmartOrder = false;
                smartOrderSide = side;
                smartOrderQuantity = qty;
                smartOrderPrice = instrument.Blotter[QuoteLevel.One].Mid;
                smartOrderStyle = OrderStyle.MarketOnClose;
            }
        }

        private void OnBlotter(object sender, Blotter e)
        {
            if (smartOrderNotYetActivated)
            {
                if (smartOrderStyle == OrderStyle.StopLimit)
                {
                    switch (smartOrderSide)
                    {
                        case OrderSide.Buy:
                            if (e[QuoteLevel.One].Mid >= smartOrderPrice)
                            {
                                instrument.Buy(OrderStyle.Limit, smartOrderPrice, smartOrderQuantity, ext, stratId);
                                smartOrderNotYetActivated = false;
                            }
                            break;
                        case OrderSide.Sell:
                            if (e[QuoteLevel.One].Mid <= smartOrderPrice)
                            {
                                instrument.Sell(OrderStyle.Limit, smartOrderPrice, smartOrderQuantity, ext, stratId);
                                smartOrderNotYetActivated = false;
                            }
                            break;
                    }
                }
                else if (smartOrderStyle == OrderStyle.Stop)
                {
                    switch (smartOrderSide)
                    {
                        case OrderSide.Buy:
                            if (e[QuoteLevel.One].Mid >= smartOrderPrice)
                            {
                                instrument.Buy(OrderStyle.Market, smartOrderPrice, smartOrderQuantity, ext, stratId);
                                smartOrderNotYetActivated = false;
                            }
                            break;
                        case OrderSide.Sell:
                            if (e[QuoteLevel.One].Mid <= smartOrderPrice)
                            {
                                instrument.Sell(OrderStyle.Market, smartOrderPrice, smartOrderQuantity, ext, stratId);
                                smartOrderNotYetActivated = false;
                            }
                            break;
                    }
                }
                else if (smartOrderStyle == OrderStyle.TrailingStopLimit)
                {
                    switch (smartOrderSide)
                    {
                        case OrderSide.Buy:
                            if (e[QuoteLevel.One].Mid >= smartOrderPrice + Amount)
                            {
                                instrument.Buy(OrderStyle.Limit, smartOrderPrice, smartOrderQuantity, ext, stratId);
                                smartOrderNotYetActivated = false;
                            }
                            else if (e[QuoteLevel.One].Mid < smartOrderPrice)
                                smartOrderPrice = e[QuoteLevel.One].Mid;
                            break;
                        case OrderSide.Sell:
                            if (e[QuoteLevel.One].Mid <= smartOrderPrice - Amount)
                            {
                                instrument.Sell(OrderStyle.Limit, smartOrderPrice, smartOrderQuantity, ext, stratId);
                                smartOrderNotYetActivated = false;
                            }
                            else if (e[QuoteLevel.One].Mid > smartOrderPrice)
                                smartOrderPrice = e[QuoteLevel.One].Mid;
                            break;
                    }
                }
                else if (smartOrderStyle == OrderStyle.TrailingStop)
                {
                    switch (smartOrderSide)
                    {
                        case OrderSide.Buy:
                            if (e[QuoteLevel.One].Mid >= smartOrderPrice + Amount)
                            {
                                instrument.Buy(OrderStyle.Market, smartOrderPrice, smartOrderQuantity, ext, stratId);
                                smartOrderNotYetActivated = false;
                            }
                            else if (e[QuoteLevel.One].Mid < smartOrderPrice)
                                smartOrderPrice = e[QuoteLevel.One].Mid;
                            break;
                        case OrderSide.Sell:
                            if (e[QuoteLevel.One].Mid <= smartOrderPrice - Amount)
                            {
                                instrument.Sell(OrderStyle.Market, smartOrderPrice, smartOrderQuantity, ext, stratId);
                                smartOrderNotYetActivated = false;
                            }
                            else if (e[QuoteLevel.One].Mid > smartOrderPrice)
                                smartOrderPrice = e[QuoteLevel.One].Mid;
                            break;
                    }
                }
                else if (smartOrderStyle == OrderStyle.MarketOnClose)
                {
                    if (instrument.Blotter[QuoteLevel.One].Time.TimeOfDay >= instrument.StaticData.Exchange.CloseAuctions &&
                       instrument.Blotter[QuoteLevel.One].Time.TimeOfDay <= instrument.StaticData.Exchange.Closing)
                    {
                        switch (smartOrderSide)
                        {
                            case OrderSide.Buy:
                                instrument.Buy(OrderStyle.Market, smartOrderPrice, smartOrderQuantity, new OrderExtension(), stratId);
                                smartOrderNotYetActivated = false;
                                break;
                            case OrderSide.Sell:
                                instrument.Sell(OrderStyle.Market, smartOrderPrice, smartOrderQuantity, new OrderExtension(), stratId);
                                smartOrderNotYetActivated = false;
                                break;
                        }
                        new RemotingLogClient().Trace(
                            new FireMessageEventArgs(
                                smartOrderSide + " LimitOnClose Order working for: " + instrument.StaticData.Name, Time.Now.TimeOfDay));
                    }
                }
                else if (smartOrderStyle == OrderStyle.LimitOnClose)
                {
                    if (instrument.Blotter[QuoteLevel.One].Time.TimeOfDay >= instrument.StaticData.Exchange.CloseAuctions &&
                        instrument.Blotter[QuoteLevel.One].Time.TimeOfDay <= instrument.StaticData.Exchange.Closing)
                    {
                        switch (smartOrderSide)
                        {
                            case OrderSide.Buy:
                                instrument.Buy(OrderStyle.Limit, smartOrderPrice, smartOrderQuantity, new OrderExtension(), stratId);
                                smartOrderNotYetActivated = false;
                                break;
                            case OrderSide.Sell:
                                instrument.Sell(OrderStyle.Limit, smartOrderPrice, smartOrderQuantity, new OrderExtension(), stratId);
                                smartOrderNotYetActivated = false;
                                break;
                        }
                        new RemotingLogClient().Trace(
                            new FireMessageEventArgs(
                                smartOrderSide + " LimitOnClose Order working for: " + instrument.StaticData.Name, Time.Now.TimeOfDay));
                    }
                }
                else if(isBracketOrder)
                {
                    switch (smartOrderSide)
                    {
                        case OrderSide.Buy:
                            if (e[QuoteLevel.One].Mid >= StopLossBracket)
                            {
                                smartOrderNotYetActivated = false;
                                instrument.Buy(OrderStyle.Limit, StopLossBracket, smartOrderQuantity, ext, stratId);

                            }
                            else if (e[QuoteLevel.One].Mid <= TakeProfitBracket)
                            {
                                smartOrderNotYetActivated = false;
                                instrument.Buy(OrderStyle.Limit, TakeProfitBracket, smartOrderQuantity, ext, stratId);

                            }
                             
                            break;
                        case OrderSide.Sell:
                            if (e[QuoteLevel.One].Mid >= TakeProfitBracket)
                            {
                                smartOrderNotYetActivated = false;
                                instrument.Sell(OrderStyle.Limit, TakeProfitBracket, smartOrderQuantity, ext, stratId);

                            }
                            else if (e[QuoteLevel.One].Mid <= StopLossBracket)
                            {
                                smartOrderNotYetActivated = false;
                                instrument.Sell(OrderStyle.Limit, StopLossBracket, smartOrderQuantity, ext, stratId);

                            }
                            break;
                    }
                }
            }
        }

        #region IDisposable Members

        void IDisposable.Dispose()
        {
            instrument.OnBlotter -= OnBlotter;
        }

        #endregion
    }
}
